package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.exception.CustomException;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.TaskService;
import com.heima.wemedia.service.WmAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.logging.Handler;
import java.util.stream.Collectors;

/**
 * @author jack
 * @data 2023 11:06
 */
@Service
@Transactional
@Slf4j
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    private WmMaterialMapper wmMaterialMapper;
    @Autowired
    private WmAutoScanService wmAutoScanService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;

    /**
     * 查询内容列表 - 多条件分页查询
     *
     * @param wmNewsPageReqDto
     * @return
     */
    @Override
    public ResponseResult findByPage(WmNewsPageReqDto wmNewsPageReqDto) {
        //1. 参数校验
        if (wmNewsPageReqDto == null)
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        wmNewsPageReqDto.checkParam();

        //2. 创建一个Page对象
        Page page = new Page(wmNewsPageReqDto.getPage(),wmNewsPageReqDto.getSize());

        //3. 创建一个Wrapper对象
        LambdaQueryWrapper<WmNews> wrapper = Wrappers.<WmNews>lambdaQuery()
                .like(StringUtils.isNotBlank(wmNewsPageReqDto.getKeyword()), WmNews::getTitle, wmNewsPageReqDto.getKeyword())
                .eq(wmNewsPageReqDto.getChannelId() != null, WmNews::getChannelId, wmNewsPageReqDto.getChannelId())
                .eq(wmNewsPageReqDto.getStatus() != null,WmNews::getStatus,wmNewsPageReqDto.getStatus())
                .ge(wmNewsPageReqDto.getBeginPubDate() != null, WmNews::getPublishTime, wmNewsPageReqDto.getBeginPubDate())
                .le(wmNewsPageReqDto.getEndPubDate() != null, WmNews::getPublishTime, wmNewsPageReqDto.getEndPubDate());

        wrapper.orderByDesc(WmNews::getCreatedTime);
        //4. 分页条件查询
        page(page,wrapper);

        //5. 返回结果
        PageResponseResult prr = new PageResponseResult((int)page.getCurrent(),(int)page.getSize(),(int)page.getTotal());
        prr.setCode(AppHttpCodeEnum.SUCCESS.getCode());
        prr.setErrorMessage(AppHttpCodeEnum.SUCCESS.getErrorMessage());
        prr.setData(page.getRecords());

        return prr;
    }

    /**
     * 发布文章
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult submit(WmNewsDto dto) {
        //1. 数据校验和处理: a. 封面类型type自动的情况  b.封面图片images
        if (dto == null || StringUtils.isBlank(dto.getContent()))
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);

        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(dto,wmNews);

        if (dto.getType().equals((short)-1)){
            wmNews.setType(null);
        }

        String images = String.join(",", dto.getImages());
        wmNews.setImages(images);

        //2. 文章的新值或者修改
        saveOrUpdateNews(wmNews);

        //2.1 判断是否为草稿，如果是草稿，流程结束
        if (dto.getStatus().equals((short)0))
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);

        //3. 不是草稿：保存内容图片和文章的关联关系
        //3.1 提取文章内容中的所有图片的url
        List<String> urlInContent = handleContentImg(dto.getContent());

        //3.2 保存内容图片和文章的关联关系
        saveRelationWithContentImg(wmNews,urlInContent);


        //4. 保存封面图片和文章的关联关系
        saveRelationWithCoverImg(wmNews,urlInContent,dto);


        //调用文章审核逻辑，对文章进行内容安全审核
        //wmAutoScanService.scanNews(wmNews.getId());

        //添加一个审核文章的任务
        taskService.addTask(wmNews);

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 文章上下架
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //1. 校验参数
        if (dto == null || dto.getId() == null || dto.getEnable() == null)
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);

        //2. 校验文章是否存在
        WmNews news = getById(dto.getId());
        if (news == null)
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);

        //3. 校验文章的状态是否是：已发布
        if (!news.getStatus().equals(WmNews.Status.PUBLISHED.getCode()))
            throw new CustomException(AppHttpCodeEnum.ARTICLE_DOWN_OR_UP_INFO);

        //4. 修改文章enable字段
        news.setEnable(dto.getEnable());
        updateById(news);

        //5. 发送消息到kafka
        Map<String,Object> map = new HashMap<>();
        map.put("aritlceId",news.getArticleId());
        map.put("enable",dto.getEnable());
        kafkaTemplate.send("down_or_up_article_topic", JSON.toJSONString(map));
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 保存封面图片和文章的关联关系
     * @param wmNews    文章
     * @param urlInContent  内容图片
     * @param dto   前端提交的文章的所有信息，包含：封面图片
     * tips: 两个核心职责：
     *   职责1： 适配封面为自动的情况：
     *              a. 当封面图片为自动时，如果内容图片数量 >=1 && < 3 ,适配为：单图  wmNews.setType(1),提取内容图片的第一张作为封面图片
     *              b. 当封面图片为自动时，如果内容图片数量 >=3 ,适配为：三图  wmNews.setType(3),提取内容图片的前三张作为封面图片
     *              c. 当封面图片为自动时，如果内容图片数量 ==0 ,适配为：无图  wmNews.setType(0)
     *
     *  职责2： 保存封面图片和文章的关联关系：type:1封面引用
     */
    private void saveRelationWithCoverImg(WmNews wmNews, List<String> urlInContent, WmNewsDto dto) {
        //获取前端传的封面图片
        List<String> images = dto.getImages();

        //职责1： 适配封面为自动的情况
        if (dto.getType().equals((short)-1)){
            //如果内容图片数量 >=1 && < 3 ,适配为：单图
            if (urlInContent != null && urlInContent.size() >= 1 && urlInContent.size() < 3){
                wmNews.setType((short)1);
                images = urlInContent.stream().limit(1).collect(Collectors.toList());
            }else if (urlInContent != null && urlInContent.size() >= 3){
                //如果内容图片数量 >=3 ,适配为：三图
                wmNews.setType((short)3);
                images = urlInContent.stream().limit(3).collect(Collectors.toList());
            }else {
                //如果内容图片数量 ==0 ,适配为：无图
                wmNews.setType((short)3);
            }

            if (images != null && images.size() > 0){
                String imgs = String.join(",", images);
                wmNews.setImages(imgs);
            }

            //修改文章信息：这里主要改的是文章的type
            updateById(wmNews);
        }

        //职责2： 保存封面图片和文章的关联关系：type:1封面引用
        saveRelationWithImg(wmNews,images,(short)1);
    }

    //保存内容图片和文章的关联关系
    private void saveRelationWithContentImg(WmNews wmNews, List<String> urlInContent) {
        saveRelationWithImg(wmNews,urlInContent,(short)0);     //0: 当前图片对文章是内容引用
    }

    /**
     * 保存图片和文章的关联关系
     * @param wmNews    文章
     * @param urlInContent  图片url集合
     * @param type  图片引用类型：0内容引用;1封面引用
     */
    private void saveRelationWithImg(WmNews wmNews, List<String> urlInContent, Short type) {
        if (urlInContent != null && urlInContent.size() >0) {
            //1. 根据图片的url查询图片的id
            List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, urlInContent));
            List<Integer> materialIds = wmMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());

            //2. 保存图片和文章的关联关系
            wmNewsMaterialMapper.saveNewsMaterials(materialIds, wmNews.getId(), type);
        }
    }

    //提取文章内容图片
    private List<String> handleContentImg(String content) {
        JSONArray jsonArray = JSONArray.parseArray(content);

        List<String> res = new ArrayList<>();

        for (Object obj : jsonArray) {
            JSONObject jsonObject = JSONObject.parseObject(obj.toString());
            if ("image".equals(jsonObject.getString("type"))){
                res.add(jsonObject.getString("value"));
            }
        }

        return res;
    }

    //新增或修改文章信息
    private void saveOrUpdateNews(WmNews wmNews) {
        if (wmNews.getId() != null){
            //1. 修改文章信息
            updateById(wmNews);
            //2. 移除文章和原有素材关联关系
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                    .eq(WmNewsMaterial::getNewsId,wmNews.getId()));

        }else{
            //新增
            wmNews.setCreatedTime(new Date());
            wmNews.setUserId(WmThreadLocalUtil.getUser().getId());
            save(wmNews);
        }
    }
}
